#include "./proto.h"
#include "../utils/encode.h"
#include "../utils/alg.h"

namespace conn::proto {

using namespace utils;

/**
 * @brief 
 * 0xE1 0x1E
 * 7
 * 0 
 * seq
 * 0^seq
 * 0xEF
 */
uint8_t make_ack(uint8_t *buf, uint8_t seq) {
    encode<uint16_t>(buf, frame::HEAD);
    encode<uint8_t>(buf + 2, 7);
    encode<uint8_t>(buf + 3, type::ACK);
    encode<uint8_t>(buf + 4, seq);

    uint8_t sum = alg::sum_xor(buf + 3, 2);

    encode<uint8_t>(buf + 5, sum); // checksum
    encode<uint8_t>(buf + 6, frame::END);

    return 7;
}

uint8_t make_res(uint8_t *buf, uint8_t seq, uint8_t cmd, uint8_t data_len) {
    encode<uint16_t>(buf, frame::HEAD);
    encode<uint8_t>(buf + 2, data_len + 8);
    encode<uint8_t>(buf + 3, type::RES);
    encode<uint8_t>(buf + 4, seq);
    encode<uint8_t>(buf + 5, cmd);

    uint8_t sum = alg::sum_xor(buf + 3, data_len + 3);
    encode<uint8_t>(buf + 6 + data_len, sum);
    encode<uint8_t>(buf + 7 + data_len, frame::END);

    return data_len + 8;
}

uint8_t make_notify_ack(uint8_t *buf, uint8_t seq, uint8_t cmd, uint8_t data_len) {
    encode<uint16_t>(buf, frame::HEAD);
    encode<uint8_t>(buf + 2, data_len + 8);
    encode<uint8_t>(buf + 3, type::NOTIFY_ACK);
    encode<uint8_t>(buf + 4, seq);
    encode<uint8_t>(buf + 5, cmd);

    uint8_t sum = alg::sum_xor(buf + 3, data_len + 3);
    encode<uint8_t>(buf + 6 + data_len, sum);
    encode<uint8_t>(buf + 7 + data_len, frame::END);

    return data_len + 8;
}

uint8_t make_notify(uint8_t *buf, uint8_t cmd, uint8_t data_len) {
    encode<uint16_t>(buf, frame::HEAD);
    encode<uint8_t>(buf + 2, data_len + 7);
    encode<uint8_t>(buf + 3, type::NOTIFY);
    encode<uint8_t>(buf + 4, cmd);

    uint8_t sum = alg::sum_xor(buf + 3, data_len + 2);
    encode<uint8_t>(buf + 5 + data_len, sum);
    encode<uint8_t>(buf + 6 + data_len, frame::END);

    return data_len + 7;
}

uint8_t make_result(uint8_t *buf, uint8_t cmd, uint8_t data_len) {
    encode<uint16_t>(buf, frame::HEAD);
    encode<uint8_t>(buf + 2, data_len + 7);
    encode<uint8_t>(buf + 3, type::RESULT);
    encode<uint8_t>(buf + 4, cmd);

    uint8_t sum = alg::sum_xor(buf + 3, data_len + 2);
    encode<uint8_t>(buf + 5 + data_len, sum);
    encode<uint8_t>(buf + 6 + data_len, frame::END);

    return data_len + 7;
}

}
